<!-- ALL-可视化巡检 -->
<template>
  <div>
    <div class="equip-wrap-common">
      <div class="equip-group-list">
        <px-input v-model="listSearch" class="w-[380px] mb-[8px] self-center" placeholder="请输入" :prefix-icon="Search" @change="listSearchFun" />
        <px-scrollbar :key="forceUpdate">
          <div
            v-for="item in searchList"
            :key="item.id"
            class="equip-group-list-item"
            :class="{ 'item-active': equipSelected?.id === item.id }"
            @click="equipGroupSelect(item)"
          >
            <div class="equip-group-list-item-title">
              <ReTextTooltip :content="item.routeName" :style="{ width: '100%' }" />
            </div>
            <px-dropdown v-if="isBtnListShow">
              <px-icon :size="16">
                <MoreFilled />
              </px-icon>
              <template #dropdown>
                <px-dropdown-menu>
                  <px-dropdown-item>
                    <px-button v-has="'ERC_INSPECT_GROUP_EDIT_GROUP'" link type="primary" :icon="EditPen" @click="groupEdit(item)">编辑</px-button>
                  </px-dropdown-item>
                  <px-dropdown-item>
                    <px-button v-has="'ERC_INSPECT_GROUP_DEL_GROUP'" link type="danger" :icon="Delete" @click="groupDelete(item)"
                      >移除</px-button
                    ></px-dropdown-item
                  >
                </px-dropdown-menu>
              </template>
            </px-dropdown>
          </div>
        </px-scrollbar>
        <px-button v-has="'ERC_INSPECT_GROUP_ADD_GROUP'" type="primary" plain class="w-[380px] self-center" @click="isView = true"
          >新增巡检路线</px-button
        >
      </div>
      <div class="equip-group-table">
        <px-button
          v-has="'ERC_INSPECT_GROUP_ADD_OPT'"
          :disabled="!routeCode"
          type="primary"
          size="small"
          border
          class="w-[116px] h-[32px] mb-[10px]"
          @click="addTableItem"
          >添加巡检位置</px-button
        >
        <div class="overflow-auto">
          <px-table
            ref="tableRef"
            table-layout="auto"
            :data="tableData"
            class="custom-form-ui equip-table"
            header-cell-class-name="equip-group-table-header"
          >
            <px-table-column prop="drag" align="center" width="70px" label="拖拽">
              <px-icon><ViewList /></px-icon>
            </px-table-column>
            <px-table-column min-width="100px" prop="operateId" label="位置名称">
              <template #default="scope">
                <px-text class="mx-1">{{ scope.row.itemName }}</px-text>
              </template>
            </px-table-column>
            <px-table-column min-width="200px" prop="operateId" label="位置路径">
              <template #default="scope">
                <px-text class="mx-1">{{ scope.row.zhPath }}</px-text>
              </template>
            </px-table-column>
            <px-table-column max-width="60px" prop="playTime" label="巡检时间(s)">
              <template #default="scope">
                <px-input-number v-model="scope.row.playTime" :min="10" :step="10" @blur="handleBlur" @change="handleChange" />
              </template>
            </px-table-column>
            <px-table-column width="70px" align="center" label="操作">
              <template #default="scope">
                <div class="flex justify-between">
                  <px-button v-has="'ERC_INSPECT_GROUP_EDIT_OPT'" type="primary" link @click="itemTop(scope.row)">置顶</px-button>
                  <px-button v-has="'ERC_INSPECT_GROUP_EDIT_OPT'" type="primary" link @click="itemBottom(scope.row)">置底</px-button>
                  <px-button v-has="'ERC_INSPECT_GROUP_DEL_OPT'" type="primary" link @click="itemDelete(scope.row)">删除</px-button>
                </div>
              </template>
            </px-table-column>
          </px-table>
        </div>
      </div>
    </div>
    <px-dialog v-model="isView" destroy-on-close :title="isEditor ? '编辑路线名称' : '新增路线名称'" :close-on-click-modal="false" width="640px">
      <px-form ref="formEl" :model="dialogFrom" label-width="120px" :rules="rules" label-position="right">
        <px-form-item label="路线名称" prop="routeName">
          <px-input v-model="dialogFrom.routeName" maxlength="10" class="w-[100%]" show-word-limit />
        </px-form-item>
      </px-form>
      <template #footer>
        <span class="dialog-footer">
          <px-button @click="cancel">取消</px-button>
          <px-button type="primary" :loading="groupBtnLoading" @click="submit"> 确定 </px-button>
        </span>
      </template>
    </px-dialog>
    <AddTreeDetail
      v-model:TreedialogVisible="TreedialogVisible"
      :routeCode="routeCode"
      :selected="tableData"
      @addEquipGroupSelect="addEquipGroupSelect"
      @closeDialog="closeDialog"
    />
  </div>
</template>

<script setup lang="ts">
import { queryList, saveOrUpdate, delById, queryListTable, top, bottom, delTableId } from "@/api/visual/inspection";
import ReTextTooltip from "@/components/ReTextTooltip";
import { getEmployeeIdAndName } from "@/utils/pengxi";
import { Delete, EditPen, MoreFilled, Search } from "@px-ui/icons-vue";
import { computed, onMounted, reactive, ref, toRefs, nextTick } from "vue";
import AddTreeDetail from "./components/AddTreeDetail.vue";
import { PxMessage, PxMessageBox } from "px-ui";
import Sortable from "sortablejs";

import { saveOrUpdateBatch } from "@/api/visual/inspection";

defineOptions({
  name: "ERC_INSPECT_GROUP"
});
const routeCode = ref("");
const formEl = ref();
const tableRef = ref();
const groupBtnLoading = ref(false);
const state = reactive<any>({
  isView: false, //新增弹窗显示
  isEmpty: true, //空页面显示
  isEditor: false, //编辑弹框
  isBtnListShow: true, //下拉按钮列表
  listSearch: "",
  searchList: [],
  forceUpdate: 0,
  queryParams: {
    pageNum: 1,
    pageSize: 20
  },
  equipGroup: [],
  equipSelected: {},
  dialogFrom: {
    routeName: ""
  },
  rules: {
    routeName: { required: true, message: "请输入路线名称", trigger: ["blur", "change"] }
  },
  tableData: [],
  peopleList: [], //下拉选人
  TreedialogVisible: false
});
const {
  isView,
  isEmpty,
  isEditor,
  equipSelected,
  listSearch,
  peopleList,
  tableData,
  dialogFrom,
  rules,
  equipGroup,
  forceUpdate,
  isBtnListShow,
  TreedialogVisible
} = toRefs(state);
const searchList = computed(() => {
  if (!listSearch.value && listSearch.value !== 0) {
    //这里数据刷新但是页面不刷新使用forceUpdate使组件强刷
    return equipGroup.value;
  }
  return equipGroup.value?.filter(item => item?.routeName?.indexOf(listSearch.value) !== -1);
});

onMounted(async () => {
  await getEuipGroup();
  peopleList.value = await getEmployeeIdAndName(["HSE", "ISEP", "ERC&FP"]); //下拉选人
});
//点击左侧列表
function equipGroupSelect(item) {
  equipSelected.value = item;
  routeCode.value = item?.routeCode;
  if (item?.routeCode) {
    getOperateTable(item?.routeCode);
  }
}
//巡检位置新增完成需要选中回显
function addEquipGroupSelect(routeCode) {
  if (routeCode) {
    getOperateTable(routeCode);
  }
}
//左侧巡检路线列表
async function getEuipGroup() {
  try {
    equipGroup.value = await queryList({
      routeName: dialogFrom.value.routeName
    });
    isEmpty.value = false;
  } catch (e) {
    console.log(e);
  }
}
//右侧表格
async function getOperateTable(routeCode) {
  try {
    tableData.value = await queryListTable({ routeCode });
    setTableTime();
    nextTick(() => {
      rowDrag();
    });
  } catch (e) {
    console.error(e);
  }
}
function setTableTime() {
  tableData.value.forEach(item => {
    const { playTime } = item;
    if (!playTime) {
      item.playTime = 60;
    }
  });
}
//左侧巡检路线编辑按钮
function groupEdit(item) {
  Object.assign(dialogFrom.value, item);
  isView.value = true;
  isEditor.value = true;
}
//左侧巡检路线删除按钮
function groupDelete(item) {
  const { id, routeName } = item;

  PxMessageBox.confirm(`是否删除${routeName}？`, "温馨提示", {
    confirmButtonText: "删除",
    confirmButtonClass: "px-button--danger",
    cancelButtonText: "取消",
    type: "warning",
    draggable: true
  })
    .then(async () => {
      await delById({ id });
      PxMessage.success("删除成功");
      equipGroup.value = await queryList({
        routeName: ""
      });
      tableData.value = null;
    })
    .catch(() => {});
}
const topButton = async row => {
  await top(row);
  await saveOrUpdateBatch(tableData.value);
  await addEquipGroupSelect(row.routeCode);
};
const bottomButton = async row => {
  await bottom(row);
  await saveOrUpdateBatch(tableData.value);
  await addEquipGroupSelect(row.routeCode);
};
//右侧置顶按钮
async function itemTop(row) {
  tableData.value = reorderByItemKey(tableData.value, row);
  topButton(row);
}
//右侧置底按钮
const itemBottom = row => {
  tableData.value = reorderByItemKey(tableData.value, row, "bottom");
  bottomButton(row);
};
//右侧表格删除按钮
function itemDelete(row) {
  const { id } = row;

  PxMessageBox.confirm(`是否删除该数据？`, "温馨提示", {
    confirmButtonText: "删除",
    confirmButtonClass: "px-button--danger",
    cancelButtonText: "取消",
    type: "warning",
    draggable: true
  })
    .then(async () => {
      const { id: routeCode } = equipSelected.value;
      await delTableId({ ids: [id] });
      await addEquipGroupSelect(row.routeCode);
      PxMessage.success("删除成功");
    })
    .catch(e => {
      console.error(e);
    });
}
function listSearchFun() {
  console.log("search", listSearch.value);
}

function cancel() {
  formEl.value?.resetFields();
  //不知道为啥resetFields无效需要手动再清理一下
  dialogFrom.value = {
    routeName: ""
  };
  isView.value = false;
  isEditor.value = false;
}
async function submit() {
  if (!formEl.value) return;
  await formEl.value.validate(async valid => {
    if (valid) {
      try {
        groupBtnLoading.value = true;
        await saveOrUpdate(dialogFrom.value);
        groupBtnLoading.value = false;
        //再调一次刷新左侧列表
        equipGroup.value = await queryList({
          routeName: ""
        });
        isView.value = false;
        //强刷左侧列表，推测是key为id但是编辑后id不变导致页面不刷新
        forceUpdate.value++;
        if (equipGroup?.value && equipGroup.value.length > 0) {
          //编辑时不切换焦点
          if (!isEditor.value) {
            equipGroupSelect(equipGroup.value[equipGroup.value.length - 1]);
          }
        }
        if (equipGroup?.value?.length > 0) {
          isEmpty.value = false;
          cancel();
        }
      } catch (e) {
        console.error(e);
        groupBtnLoading.value = false;
      }
    }
  });
}
//新增巡检位置按钮
function addTableItem() {
  TreedialogVisible.value = true;
}
// 取消按钮
const closeDialog = () => {
  TreedialogVisible.value = false;
};

// 表格行拖拽移动
const rowDrag = () => {
  const el = tableRef?.value?.$el.querySelector("tbody");
  Sortable.create(el, {
    animation: 180,
    delay: 0,
    onEnd: ({ newIndex, oldIndex }) => {
      tableData.value.splice(newIndex, 0, tableData.value.splice(oldIndex, 1)[0]);
      const newTable = tableData.value.splice(0);
      tableData.value = [];
      nextTick(() => {
        tableData.value = newTable;
        saveOrUpdateBatch(newTable);
      });
    }
  });
};

/**
 * 根据对象字段值将某项置顶或置底
 * @param {Array<Object>} arr - 原始对象数组
 * @param {*} value - 匹配字段的值
 * @param {string} position - 'top' 或 'bottom'
 * @param {string} key - 匹配字段名，默认为 'id'
 * @returns {Array<Object>} - 新的排序数组
 */
function reorderByItemKey(arr, value, position = "top", key = "id") {
  if (!Array.isArray(arr)) throw new Error("arr 必须是数组");
  if (!["top", "bottom"].includes(position)) {
    throw new Error("position 只能为 'top' 或 'bottom'");
  }

  const index = arr.findIndex(item => item[key] === value[key]);
  if (index === -1) return [...arr]; // 如果没找到，返回原数组副本

  const target = arr[index];
  const rest = arr.slice(0, index).concat(arr.slice(index + 1));

  return position === "top" ? [target, ...rest] : [...rest, target];
}
let timeout = null;
const handleChange = val => {
  // 缓存变更值，延迟调用，避免频繁请求
  if (timeout) clearTimeout(timeout);
  timeout = setTimeout(async () => {
    await saveOrUpdateBatch(tableData.value);
  }, 500); // debounce 时间可调
};

const handleBlur = async () => {
  if (timeout) clearTimeout(timeout);
  tableData.value.forEach(item => {
    const { playTime } = item;
    if (!playTime) {
      item.playTime = 10;
    }
  });
  await saveOrUpdateBatch(tableData.value);
};
</script>

<style lang="scss" scoped>
@import url("@/views/all/equip/scss/table-list.scss");

.equip-wrap-common {
  display: flex;
  min-width: 1100px;

  .equip-group-list {
    display: flex;
    flex-direction: column;
    flex-grow: 0;
    flex-shrink: 0;
    align-items: flex-end;
    width: 400px;
    height: 100%;
    padding-top: 16px;
    padding-bottom: 16px;
    border-right: 1px solid #dcdcdc;

    &-item {
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: space-between;
      width: 380px;
      height: 62px;
      padding-right: 14px;
      cursor: pointer;
      box-shadow: inset 0 -1px 0 0 rgb(0 0 0 / 10%);

      &-title {
        display: flex;
        flex-direction: column;
        flex-grow: 1;
        align-items: flex-start;
        justify-content: center;
        width: 90%;
        height: 100%;
        padding-left: 16px;
        margin-bottom: 3px;
        font-size: 14px;

        .title-tag {
          display: flex;
          align-items: center;
          justify-content: center;
          width: auto;
          height: 22px;
          padding: 8px;
          font-size: 12px;
          font-weight: 400;
          line-height: 20px;
          color: #909399;
          background: #f4f4f5;
          border: 1px solid #e9e9eb;
          border-radius: 4px;
        }
      }

      i,
      svg {
        outline: none;
      }
    }

    .item-active {
      background: #ecf5ff;
      border-right: 2px solid #3b82f6;
      box-shadow: inset 0 -1px 0 0 rgb(0 0 0 / 10%);

      & > :first-child {
        color: #3b82f6;
      }
    }
  }

  .equip-group-table {
    display: flex;
    flex-direction: column;
    flex-grow: 1;
    min-width: 700px;
    height: 100%;
    padding: 16px 24px;
  }

  :deep(.equip-group-table-header) {
    background: #ebedf0;
  }
}
</style>
